<?php
namespace Monkey;

use MonkeyException;

/**
 * 路由管理器\Monkey\RouteManager
 * @package    Monkey
 * @author     HuangYi
 * @copyright  Copyright (c) 2011-07-01——2013-03-30
 * @license    New BSD License
 * @version    $Id: \Monkey\RouteManager.php 版本号 2013-03-30 $
 */
final class RouteManager
{
    private static $_instance;
    private static $_config=array(
        'search_mode'   =>'rewrite',//三个选择：rewrite（需服务器支持）、pathinfo（需服务器支持）、get（传统方式）
        'search_get'    =>'r', //get字段上的显式方法设置，如http://www.xxx.php?r=index
        'default'       =>'index', //默认控制器
        'suffix'        =>'.html', //网址修饰符，使得网址看起来像静态网页，这对搜索引擎友好些
    );
    private static $_router_library_file='/config/router.data.php';
    private static $_routerTable;       //路由数据表
    private static $_request;     //当前路由字符串
    private static $_router;    //当前路由器
    private static $_params=''; //当前路由参数
    private function __construct(){
        self::$_config=$config=oApp()->routeSet;
        self::$_router=$config['default'];
        $mode=$config['search_mode'];
        self::$_request='';
        if($mode=='rewrite' or $mode=='pathinfo'){
            self::$_request=$this->_getPath($config['suffix']);
        }elseif(isset($_GET[$config['search_get']])){
            self::$_request=$_GET[$config['search_get']];
        }
    }
    public static function _instance(){
        !self::$_instance and self::$_instance=new self();
        return self::$_instance;
    }
    /**
     * @param null $file
     * @return \Monkey\RouteManager
     */
    public function fetchTable($file=null){
        if($file || !self::$_routerTable){
            !$file and $file=SYSTEM.self::$_router_library_file;
            self::$_routerTable=include($file);
        }
        return $this;
    }
    /**
     * @param null $routerTable
     * @param null $file
     * @return \Monkey\RouteManager
     */
    public function storeTable($routerTable=null,$file=null){
        !$routerTable and $routerTable=self::$_routerTable;
        !$file and $file=SYSTEM.self::$_router_library_file;
        fileSaveVariable($file, $routerTable);
        return $this;
    }
    /**
     * 分发路由
     */
    public function dispatch(){
        $this->fetchTable();
        $this->_parseRoute();
        $this->_startController(self::$_routerTable[self::$_router]);
    }
    /**
     * @param string $name 控制器名
     * @return \Monkey\Controller\_Interface object 控制器对象
     */
    public function controller($name){
        if(!import(SYSTEM.'/Controller/'.$name.'.php')){
            MonkeyException::halt('控制器丢失！',1024,__FILE__,__LINE__);
        }
        $class=new \ReflectionClass('Controller\\'.$name);//建立反射类
        if(!$class->implementsInterface('Monkey\\Controller\\_Interface'))
            MonkeyException::halt('控制器不规范！',1024,__FILE__,__LINE__);
        return $class->newInstance();
    }
    private function _startController($router){
        if(empty($router) || !$router['enable'])MonkeyException::show404();
        if(!empty($router['role'])){
            if(!$this->_checkAuthority($router['role']))
                MonkeyException::show403();//无权访问
        }
        $control=$this->controller($router['controller']);//
        //if(!Plugin()->before($router['controller'],self::$_params)) return;
        $control->bootup($router['action'],self::$_params);
        //Plugin()->after($router['controller'],self::$_params);
    }
    private function _checkAuthority($role){
        return true;//还没做，后来补上
    }
    /**
     * 路由组装
     * @param string $router 路由器名
     * @param string $params 参数
     * @param bool $getUrl 为TRUE则返回URL（默认），为FALSE则返回route
     * @return string
     */
    public function package($router=null,$params=null,$getUrl=true) {
        $router=  trim($router);
        $params= trim($params);
        $route = ($router && $params)? $router.'/'.$params:$router.$params;
        if(!$getUrl)return $route;
        return $this->_package($route);
    }
    public function getRoute($repack=true){
        if(!$repack)return self::$_request;
        static $route=null;
        !$route and $route=(self::$_router && self::$_params)? self::$_router.'/'.self::$_params:self::$_router.self::$_params;
        return $route;
    }
    public function getRouter(){
        return self::$_router;
    }
    public function getParams(){
        return self::$_params;
    }
    public function getControllerName(){
        return self::$_routerTable[self::$_router]['controller'];
    }
    public function getAction(){
        return self::$_routerTable[self::$_router]['action'];
    }
    public function getURL($repack=true){
        return $this->_package($this->getRoute($repack));
    }
    public function getSuffix(){
        return self::$_config['suffix'];
    }
/************************辅助方法*************************/
    private function _package($route){
        $config=self::$_config;
        static $entrance;
        !$entrance and $entrance=oApp()->entranceSet;
        $_route=$route ? '/'.$route:'';
        if($config['search_mode']=='rewrite'){
            return __INDEX__.$_route ;
        } elseif($config['search_mode']=='pathinfo'){
            return __INDEX__.'/'.$entrance.$_route ;
        } else{
            return __INDEX__.'/'.$entrance.'?'.($route ? $config['search_get'].'='.$route:'' );
        }
    }
    private function _getPath($suffix){
        if(isset($_SERVER['REQUEST_URI'])) $url = $_SERVER['REQUEST_URI'];
        if(!isset($url) && isset($_SERVER['HTTP_X_REWRITE_URL'])) $url = $_SERVER['HTTP_X_REWRITE_URL'];//修正IIS中ISAPI_Rewrite的重新定义网址问题
        $url=explode('?', $url);
        $url=substr($url[0],strlen(__INDEX__));
        $url[0]=='/' and $url=substr($url,1);
        if(substr($url, 0, 9)=='index.php'){
            $temp=substr($url, 9);
            if(empty($temp)) return '';
            $temp[0]=='/' and $url = substr($temp, 1);
        }
        $fix_len = strlen($suffix);
        $url_len = strlen($url);
        if($url_len > $fix_len && substr($url,0-$fix_len) == $suffix){
            $url=substr($url,0,$url_len-$fix_len);
        }
        return $url;
    }

    ///////////////////////
    private function _parseRoute(){
        $request=self::$_request;
        if(empty($request)) return;
        $request=explode('/',$request);
        $count=count($request);
        $router=$request[0];
        $k=0;//已匹配节数
        while(1){
            if(!isset(self::$_routerTable[$router]))break;
            self::$_router=$router;
            $k++;
            if($k==$count)break;
            $router.='/'.$request[$k];
        }
        if($k==0){
            self::$_params=$request;
        }elseif($k==$count){
            self::$_params='';
        }else{
            $request=array_slice($request,$k);
            self::$_params=implode('/',$request);
        }
    }
}